/* © 2007 Adobe Systems Incorporated. All rights reserved. */
package com.shubhjai.musiclib.managers
{
	import flash.display.NativeWindow;
	import flash.events.Event;
	import flash.events.NativeWindowBoundsEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.SharedObject;
	import flash.system.Capabilities;
	import flash.utils.Timer;
	
	import mx.effects.AnimateProperty;
	import mx.events.EffectEvent;
	import flash.system.System;
	
	/**
	 * This class manages some specific situations where we want to move the window to ensure its on screen.
	 */ 
	public class WindowPositionManager
	{
		private static var instance : WindowPositionManager
		
		private var window : NativeWindow;
		private var so : SharedObject;
		private var inited : Boolean;
		
		private var origBounds : Rectangle;
		private var ensureHeightVal : Number;
		private var moveEffect : AnimateProperty;
		
		private var timer1 : Timer;
		private var timer2 : Timer;
		private var winPos : Point;

	
		/**
		 * Private constructor.
		 */ 
		public function WindowPositionManager() 
		{
			if ( instance != null )
			{
				throw new Error( "Private constructor. Use getInstance() instead." );
				
				inited = false;
			}
			ensureHeightVal = 0;
			moveEffect = new AnimateProperty();
			
			timer1 = new Timer( 500, 1 );
			timer1.addEventListener( TimerEvent.TIMER, doHeightCheck );
			
			timer2 = new Timer( 700, 1 );
			timer2.addEventListener( TimerEvent.TIMER, doReturnAnim );
			
			so = SharedObject.getLocal( "appPos" );
			
			
		}
		
		/**
		 * Get an instance of the location manager.
		 */ 
		public static function getInstance() : WindowPositionManager
		{
			if ( instance == null )
			{
				instance = new WindowPositionManager();
			}
			return instance;
		}
		
		/**
		 * Init the manager for the given window.
		 */ 
		public function init( window:NativeWindow ) : void
		{
			if ( ! inited )
			{
				inited = true;
				this.window = window;
				
				var lastPos : Object = so.data.lastPos;
				var maxWinSize : Point = getMaxWinSize();
				
				if ( lastPos && lastPos.x >= 0 && lastPos.y >= 0 && lastPos.x < maxWinSize.x && lastPos.y < maxWinSize.y ) 
				{
					window.x = lastPos.x;
					window.y = lastPos.y;
				}
				
				
				winPos = window.bounds.topLeft;
				
				window.addEventListener( NativeWindowBoundsEvent.MOVE, onWindowMove );
				window.addEventListener( Event.CLOSING, onWindowClosing );  // BUG: This isn't working in current Apollo build.
				window.addEventListener( Event.CLOSE, onWindowClose );
			}
		}
		
		
		
		private function onWindowMove( evt:NativeWindowBoundsEvent ) : void
		{
			origBounds = null;
			ensureHeightVal = 0;
			
			// if they move the window, stop any timeouts for manual movement.
			timer1.stop();
			timer2.stop();
			
			winPos = window.bounds.topLeft;
		}
		
		/**
		 * Ensures that the window is positioned so that it can display the given height.
		 */ 
		public function ensureOnScreen( height:Number ) : void
		{	
			//trace("ensureOnScreen(" + height + ")");
			
			if ( isNaN( ensureHeightVal ) || ensureHeightVal < height )
			{
				ensureHeightVal = height;
				timer1.reset();
				timer1.start();
			}
		}
		
		private function doHeightCheck( evt:Event ) : void
		{
			//trace("doHeightCheck: " + ensureHeightVal);
			 
			 // BUG: NativeWindowCapabilities not yet reliable.
			 //var yDelta : Number = ( window.y + ensureHeightVal ) - NativeWindowCapabilities.windowMaxSize.y;
			 var yDelta : Number = ( window.y + ensureHeightVal ) - Capabilities.screenResolutionY;
	 
			 if ( yDelta > 0 && ! moveEffect.isPlaying )
			 {
			 	if ( origBounds == null ) // we could have a previous bounds from a previous ensure
			 	{		 	
				 	origBounds = window.bounds;
			 	}
			 	
			 	moveEffect.addEventListener( EffectEvent.EFFECT_END, onEffectEnd );
			 	window.removeEventListener( NativeWindowBoundsEvent.MOVE, onWindowMove );
			 	
			 	moveEffect.duration = 800;
			 	moveEffect.property = "y";
			 	moveEffect.fromValue = window.y;
			 	moveEffect.toValue = window.y - yDelta;
			 	moveEffect.play( [ window ] );
			 
			 }
			
		}
		
		private function onEffectEnd( evt:Event ) : void
		{	
			//trace("onEffectEnd()");
			window.addEventListener( NativeWindowBoundsEvent.MOVE, onWindowMove );
			moveEffect.removeEventListener( EffectEvent.EFFECT_END, onEffectEnd );
			ensureHeightVal = 0;
		}
		
		/**
		 * Return to the original y position unless we moved.
		 */ 
		public function resetOrigPosition() : void
		{
			//trace("resetOrigPosition()");
			if ( origBounds != null  )
			{
				timer2.reset();
				timer2.start();
			}
		}
		
		private function doReturnAnim( evt:TimerEvent ) : void
		{
			//trace("doReturnAnim()");
			moveEffect.addEventListener( EffectEvent.EFFECT_END, onEffectEnd );
			window.removeEventListener( NativeWindowBoundsEvent.MOVE, onWindowMove );
			moveEffect.fromValue = window.y;
			moveEffect.toValue = origBounds.y;
			moveEffect.play( [ window ] );
		}
		
		
		private function onWindowClose( evt:Event ) : void
		{
			if ( winPos.x >= 0 && winPos.y >= 0 ) // Tricky, if its minimized it could have a negative position 
			{
				so.data.lastPos = winPos;
				var status : String = so.flush();
			}
		}
		
		/**
		 * Helper function to get the maximum window position, as best we can.
		 */ 
		private function getMaxWinSize() : Point
		{
			if ( Capabilities.os.indexOf("Windows") >= 0 )
			{
				return window.maxSize;
			}
			else
			{
				return new Point( Capabilities.screenResolutionX, Capabilities.screenResolutionY );
			}
		}
		
		private function onWindowClosing( evt:Event ) : void
		{
			trace("onWindowClosing()");	
		}
	}
}